package com.rxy.annotation;

import com.rxy.utils.GetClassUtil;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 解析Bean相关注解：@Service、@Autowired
 */
public class AnnotationRigisterBean {

    // 存储对象：key-bean实例的类类型，value-bean实例对象
    private static Map<Class<?>,Object> singleTonObjects = new HashMap<>();

    // 存储对象：key-beanId，value-bean实例对象
    private static Map<String,Object> map = new HashMap<>();

    //扫描基础包
    private static final String BASIC_PACKAGE = "com.rxy";

    static {
        parseAutowiredAnno(parseServiceAnno(BASIC_PACKAGE));
    }

    // 对外提供获取实例对象的接口（根据类类型获取）
    public static Object getBean(Class<?> classType) {
        return singleTonObjects.get(classType);
    }

    // 对外提供获取实例对象的接口（根据bean的id获取）
    public static Object getBean(String id) {
        return map.get(id);
    }

    public static Map<Class<?>, Object> getSingleTonObjects() {
        return singleTonObjects;
    }

    public static Map<String, Object> getMap() {
        return map;
    }

    /**
     * 解析@Service注解，实例化所有的bean
     * @param packageName
     * @return
     */
    private static Map<Class<?>, String> parseServiceAnno(String packageName) {
        try {
            Map<Class<?>, String> beanMap = new HashMap<>();
            //获取指定包下的所有类的全限定类名
            Set<String> classList = GetClassUtil.getClassName(packageName, true);
            for (String className : classList) {
                if(className.contains("servlet")) continue;
                //使用类加载器加载类，获取字节码对象
                Class<?> clazz = Class.forName(className);
                //判断类是否含有指定注解
                boolean isExist = clazz.isAnnotationPresent(Service.class);
                if(isExist){
                    //获取注解对象
                    Service desc = (Service)clazz.getAnnotation(Service.class);
                    //获取注解成员值
                    String beanName = desc.value();
                    if("".equals(beanName)){
                        //为beanName设置默认值（类名首字母小写）
                        beanName = clazz.getSimpleName();
                        beanName = beanName.substring(0,1).toLowerCase().concat(beanName.substring(1));
                    }
                    // 通过反射技术实例化对象
                    Object object = clazz.newInstance();
                    Class<?>[] interfaces = clazz.getInterfaces();
                    // 存储到map中待用
                    singleTonObjects.put(interfaces.length == 0 ? clazz : interfaces[0], object);
                    map.put(beanName, object);
                    beanMap.put(clazz, beanName);
                }
            }
            return beanMap;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return new HashMap<>();
    }

    /**
     * 解析@Autowired注解，维护bean的依赖关系（目前只处理了字段上的注解）
     * 处理事务注解
     * @param beanMap
     */
    private static void parseAutowiredAnno(Map<Class<?>, String> beanMap) {
        //实例化完成之后维护对象的依赖关系
        try {
            Map<String, Class<?>> transBeanNameMap = new HashMap<>();
            for (Map.Entry<Class<?>, String> entry : beanMap.entrySet()) {
                Class<?> clazz = entry.getKey();
                String beanName = entry.getValue();
                Field[] fields = clazz.getDeclaredFields();
                //判断字段是否含有指定注解
                for (Field field : fields) {
                    boolean isFExist = field.isAnnotationPresent(Autowired.class);
                    if(isFExist){
                        //获取属性名称
                        String fieldName = field.getName();
                        fieldName = fieldName.substring(0,1).toLowerCase().concat(fieldName.substring(1));
                        //获取对应的属性值
                        Class<?> attrClazz = field.getType();
                        Object value = singleTonObjects.get(attrClazz);
                        // 调用父元素对象的反射功能
                        Object parentObject = map.get(beanName);
                        // 遍历父对象中的所有方法，找到"set" + name
                        Method[] methods = parentObject.getClass().getMethods();
                        for (int j = 0; j < methods.length; j++) {
                            Method method = methods[j];
                            if(method.getName().equalsIgnoreCase("set" + fieldName)) {
                                method.invoke(parentObject,value);
                            }
                        }
                    }
                }
                //判断类是否含有事务注解
                boolean isTExist = clazz.isAnnotationPresent(Transactional.class);
                if(isTExist){
                    transBeanNameMap.put(beanName, clazz);
                }
            }
            //最后处理事务注解
            AnnotationTransactionHandler.handlerTransactionBean(transBeanNameMap);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
